﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Microsoft.VisualBasic.FileIO;
using System.Collections.Specialized;

namespace TripleCComiC
{
    public partial class Browser : Form
    {
        public Browser(Form1 mainForm)
        {
            InitializeComponent();

            _mainForm = mainForm;
        }

        private void Browser_Load(object sender, EventArgs e)
        {
            LoadFolder(_mainForm.CurrentPath);
        }

        private void Browser_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (_workerLoadImage != null)
            {
                _workerLoadImage.CancelAsync();
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void _workerLoadImage_DoWork(object sender, DoWorkEventArgs e)
        {
            foreach (Control ctrl in panel_Browser.Controls)
            {
                if ((sender as BackgroundWorker).CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }

                if (ctrl is ListItem)
                {
                    try
                    {
                        (ctrl as ListItem).SetImage();
                    }
                    catch (Exception ex)
                    {
                        if (ex.Message == "Operations be cancelled.")
                        {
                            continue;
                        }
                    }
                }
            }
        }

        private void newItem_KeyDown(object sender, KeyEventArgs e)
        {
            ListItem item = sender as ListItem;
            StringCollection files = new StringCollection();

            switch (e.KeyData)
            {
                case Keys.Enter:
                    item.RunJob(null);
                    break;
                case Keys.F2:
                    item.ChangeText();
                    break;
                case Keys.Delete:
                    DeleteFile(item);
                    break;
                case Keys.Control | Keys.X:
                    files.Clear();
                    files.Add(item.Item);
                    Clipboard.SetFileDropList(files);
                    break;
                case Keys.Control | Keys.C:
                    files.Clear();
                    files.Add(item.Item);
                    Clipboard.SetFileDropList(files);
                    break;
                case Keys.Control | Keys.V:
                    if (Clipboard.ContainsFileDropList())
                    {
                        foreach (var text in Clipboard.GetFileDropList())
                        {
                            MessageBox.Show(text);
                        }
                    }
                    break;
            }
        }

        /// <summary>
        /// Move current folder to specific folder.
        /// </summary>
        /// <param name="path">Specific folder's full path.</param>
        private void LoadFolder(string path)
        {
            DirectoryInfo parent = Directory.GetParent(path);

            this.Text = path;
            _dirs = _mainForm.SortFileName(Directory.GetDirectories(path));
            _files = _mainForm.SortFileName(Directory.GetFiles(path));

            // Stop old task.
            if(_workerLoadImage != null)
            {
                _workerLoadImage.CancelAsync();
            }

            // Show current path in tool strip.
            ShowPath(new DirectoryInfo(path));

            // Clear controls.
            foreach(Control ctrl in panel_Browser.Controls)
            {
                ctrl.Dispose();
            }
            panel_Browser.Controls.Clear();

            // Add parent directory.
            panel_Browser.Controls.Add(NewParentItem(parent));
            
            foreach (string dir in _dirs)
            {
                panel_Browser.Controls.Add(NewItem(new DirectoryInfo(dir)));
            }
            foreach (string file in _files)
            {
                ListItem newItem = NewItem(new FileInfo(file));
                newItem.TextChanging += new EventHandler<ListItem.TextChangingEventArgs>((object eventSender, ListItem.TextChangingEventArgs eventArgs) =>
                {
                    ListItem listItem = (eventSender as ListItem);
                    String newPath = 
                        Directory.GetParent(listItem.Item) + @"\" + eventArgs.NewText;
                    try
                    {
                        File.Move(listItem.Item, newPath);
                        listItem.Item = newPath;
                        listItem.SetImage();
                    }
                    catch
                    {
                        throw;
                    }
                });
                panel_Browser.Controls.Add(newItem);
            }
            if(panel_Browser.Controls.Count > 0)
            {
                panel_Browser.Controls[0].Focus();
            }

            _workerLoadImage = new BackgroundWorker();
            _workerLoadImage.WorkerSupportsCancellation = true;
            _workerLoadImage.DoWork += _workerLoadImage_DoWork;
            _workerLoadImage.RunWorkerAsync();
        }
        
        /// <summary>
        /// Move current folder to my computer.
        /// </summary>
        private void LoadMyConputer()
        {
            if (_workerLoadImage != null)
            {
                _workerLoadImage.CancelAsync();
            }

            ShowPath(null);

            foreach (Control ctrl in panel_Browser.Controls)
            {
                ctrl.Dispose();
            }
            panel_Browser.Controls.Clear();
            foreach (DriveInfo driver in DriveInfo.GetDrives())
            {
                panel_Browser.Controls.Add(NewItem(driver));
            }
        }

        /// <summary>
        /// Set default setting of ListItem.
        /// </summary>
        /// <param name="item">ListItem to be set.</param>
        private void NewItemPublicSetting(ListItem item)
        {
            item.num = _itemCount++;
            item.KeyDown += newItem_KeyDown;
        }

        /// <summary>
        /// Create new item which link to parent directory.
        /// </summary>
        /// <param name="parent">Parent directory infomation.</param>
        /// <returns>New item which link to parent directory.</returns>
        private ListItem NewParentItem(DirectoryInfo parent)
        {
            ListItem newItem = new ListItem();

            NewItemPublicSetting(newItem);
            newItem.Type = ListItem.listItemType.Directory;
            newItem.Item = (parent != null) ? parent.FullName : "MyComputer";
            newItem.Text = "..";
            if (parent != null)
            {
                newItem.DoJob += new EventHandler((object eventSender, EventArgs eventArgs) =>
                {
                    LoadFolder(parent.FullName);
                });
            }
            else
            {
                newItem.DoJob += new EventHandler((object eventSender, EventArgs eventArgs) =>
                {
                    LoadMyConputer();
                });
            }

            return newItem;
        }

        /// <summary>
        /// Create new item which link to specific directory.
        /// </summary>
        /// <param name="dir">specific directory infomation.</param>
        /// <returns>New item which link to specific directory.</returns>
        private ListItem NewItem(DirectoryInfo dir)
        {
            ListItem newItem = new ListItem();

            NewItemPublicSetting(newItem);
            newItem.Type = ListItem.listItemType.Directory;
            newItem.Item = dir.FullName;
            newItem.Text = dir.Name;
            newItem.DoJob += new EventHandler((object eventSender, EventArgs eventArgs) =>
            {
                LoadFolder((eventSender as ListItem).Item);
            });

            return newItem;
        }
        /// <summary>
        /// Create new item which link to specific file.
        /// </summary>
        /// <param name="file">specific file infomation.</param>
        /// <returns>New item which link to specific file.</returns>
        private ListItem NewItem(FileInfo file)
        {
            ListItem newItem = new ListItem();

            NewItemPublicSetting(newItem);
            newItem.Type = (IsImage(file.Name)) ? ListItem.listItemType.Image : ListItem.listItemType.File;
            newItem.Item = file.FullName;
            newItem.Text = file.Name;
            newItem.DoJob += new EventHandler((object eventSender, EventArgs eventArgs) =>
            {
                _mainForm.LoadFile((eventSender as ListItem).Item);
                this.Close();
            });

            return newItem;
        }
        /// <summary>
        /// Create new item which link to specific dirver.
        /// </summary>
        /// <param name="dirver">specific dirver infomation.</param>
        /// <returns>New item which link to specific dirver.</returns>
        private ListItem NewItem(DriveInfo driver)
        {
            ListItem newItem = new ListItem();

            NewItemPublicSetting(newItem);
            newItem.Type = ListItem.listItemType.Directory;
            newItem.Item = driver.Name;
            newItem.Text = driver.Name;
            newItem.DoJob += new EventHandler((object eventSender, EventArgs eventArgs) =>
            {
                LoadFolder(driver.RootDirectory.FullName);
            });

            return newItem;
        }

        /// <summary>
        /// Indicates whether the specified file is image file.
        /// </summary>
        /// <param name="fileName">File path.</param>
        /// <returns>true if the specified file is image file; otherwise, false.</returns>
        private bool IsImage(string fileName)
        {
            string ext = Path.GetExtension(fileName).ToLower();
            return ext == ".jpg" || ext == ".jpeg"
                || ext == ".gif" || ext == ".png"
                || ext == ".bmp" || ext == ".tiff";
        }

        /// <summary>
        /// Show current path in tool strip.
        /// </summary>
        /// <param name="dir">Current path.</param>
        private void ShowPath(DirectoryInfo dir)
        {
            ToolStripButton button;
            List<ToolStripButton> list = new List<ToolStripButton>();

            strip_Path.Items.Clear();

            // Add select folder.
            button = new ToolStripButton();
            button.Text = _mainForm.Txt("dialog_SelectFolder", "Select folder");
            button.Tag = (dir != null) ?
                dir.FullName :
                Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
            button.Click += new EventHandler((object eventSender, EventArgs eventArgs) =>
            {
                FolderBrowserDialog dialog = new FolderBrowserDialog();

                dialog.Description = _mainForm.Txt("dialog_SelectFolder", "Select folder");
                dialog.SelectedPath = ((eventSender as ToolStripButton).Tag as string);
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    LoadFolder(dialog.SelectedPath);
                }
            });
            strip_Path.Items.Add(button);
            strip_Path.Items.Add(new ToolStripSeparator());

            // Add link of my computer.
            button = new ToolStripButton();
            button.Text = _mainForm.Txt("MyComputer", "My Computer") + " >";
            button.Click += new EventHandler((object eventSender, EventArgs eventArgs) =>
            {
                LoadMyConputer();
            });
            strip_Path.Items.Add(button);

            while (dir != null)
            {
                button = new ToolStripButton();

                button.Text = dir.Name + " >";
                button.Tag = dir;
                button.Click += new EventHandler((object eventSender, EventArgs eventArgs) =>
                {
                    LoadFolder(((eventSender as ToolStripButton).Tag as DirectoryInfo).FullName);
                });
                list.Add(button);

                dir = dir.Parent;
            }

            list.Reverse();

            strip_Path.Items.AddRange(list.ToArray());
        }

        /// <summary>
        /// Delete select file or directory in file system.
        /// </summary>
        /// <param name="item">file or directory to be delete.</param>
        private void DeleteFile(ListItem item)
        {
            try
            {
                FileSystem.DeleteFile(
                    item.Item,
                    UIOption.AllDialogs,
                    RecycleOption.SendToRecycleBin,
                    UICancelOption.ThrowException);
                panel_Browser.Controls.Remove(item);
            }
            catch (FileNotFoundException)
            {
                try
                {
                    FileSystem.DeleteDirectory(
                        item.Item,
                        UIOption.AllDialogs,
                        RecycleOption.SendToRecycleBin,
                        UICancelOption.ThrowException);
                    panel_Browser.Controls.Remove(item);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}
